package com.qr;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Properties;

import javax.lang.model.element.VariableElement;
import javax.management.relation.RelationException;

import com.sun.media.sound.SoftTuning;
import com.sun.scenario.effect.impl.hw.ShaderSource;
import org.junit.Test;

/**
 * 反射：
 * 		框架是应用定制的骨架
 * 		属于一个半成品软件，对应一种解决方案
 * @author bb
 */
public class Reflex {

	@Test
	public void reflexStt() throws Exception{
		
		/**
		 * 获取字节码文件的三种方式	第二个阶段
		 * 		类对象阶段获取
		 */
		Class<?> forName = Class.forName("com.qr.junit.Reflex");
		System.out.println(forName);
		
		/**
		 * 类名.class		第一个阶段
		 * 		源代码阶段获取
		 */
		Class class1 = Reflex.class;
		System.out.println(class1);
		
		/**
		 * 对象.getClass		java代码的最后一个阶段
		 * 		运行时阶段获取
		 */
		Reflex reflex = new Reflex();
		
		Class<? extends Reflex> class2 = reflex.getClass();
		System.out.println(class2);
		
		
		//结论是三种运行状态获取的都是同一个字节码文件
		
	}
	
	/**
	 * 反射获取对象：
	 * 		
	 * 
	 * 
	 */
	@Test
	public void reflexGet() throws Exception{
		Person person = new Person();
		Class<? extends Person> cls = person.getClass();

		//获取所有 public 修饰的成员变量
		//	public boolean 修饰符	 com.qr.Person.isSend所在的包和变量名称
		Field[] fields = cls.getFields();
//		System.out.println(fields);
		for (int i = 0; i < fields.length; i++) {
			System.out.println(fields[i]);
		}

		//获取指定名称的成员变量
		Field idCard = cls.getField("idCard");
		System.out.println(idCard);

		//获取所有的成员变量
		Field[] declaredFields = cls.getDeclaredFields();
		System.out.println("获取所有的成员变量");
		for (Object o :declaredFields) {
			System.out.println(o);
		}

		System.out.println("获取指定的成员变量");
		//如果nameString不存在，那么NoSuchFieldException
		Field nameString = cls.getDeclaredField("nameString");
		System.out.println(nameString);
		/**
		 * 现上面的异常说明我们无法给私有属性赋值
		 * 		IllegalAccessException: Class com.qr.Reflex can not access a member of class com.qr.Person with modifiers "private"
		 * 	需要使用暴力反射：
		 * 		setAccessible(true)
		 */
		nameString.setAccessible(true);
		nameString.set(person,"张三");


		Object o = idCard.get(person);
		//这个默认值是0
		System.out.println(o);
		idCard.set(person,20);
		System.out.println(person);

	}


	/**
	 * 获取构造
	 */
	@Test
	public void getConstruct() throws Exception{

		Person person = new Person();
		Class<? extends Person> p = person.getClass();
		//获取构造方法,这个获取的只是五参数的构造
		Constructor<? extends Person> constructor = p.getConstructor();
		System.out.println(constructor);

		System.out.println("获取所有的构造方法，除去私有构造外");
		Constructor<?>[] constructors = p.getConstructors();
		for (Object o :constructors) {
			System.out.println(o);
		}

		Constructor<? extends Person> noParamConstruct = p.getConstructor();
		System.out.println("空参数创建对象");
		System.out.println(noParamConstruct);

//		Constructor<? extends Person> constructor1 = p.getConstructor(String.class, int.class);，不存在此类构造会报错
		/**
		 * 使用类的构造方法创建对象boolean是小写
		 */
		Constructor<? extends Person> construct = p.getConstructor(int.class, String.class,boolean.class);
		System.out.println("构造方法创建对象"+construct);

		//创建对象
		Person per = construct.newInstance(20, "张三", true);
		System.out.println("构造方法创建的对象");
		System.out.println(per);


		/**
		 * 使用私有构造创建对象是需要使用
		 * 		getDeclaredConstructor这个方法的
		 * 		同时也需要暴力反射
		 */
		System.out.println("使用私有构造器创建对象");

		Constructor<? extends Person> coss = p.getDeclaredConstructor(int.class, String.class, boolean.class, int.class, double.class, int.class);
		System.out.println("私有构造创建对象也必须使用暴力反射");
		coss.setAccessible(true);
		Person perPrivate = coss.newInstance(2, "张三", false, 22, 18.8, 25);
		System.out.println(perPrivate);


	}

	/**
	 * 获取方法
	 */
	@Test
	public void getMethod() throws Exception{

		Class<Person> personClass = Person.class;
		/**
		 * 这个获取的是所有的方法包括set和get
		 * 获取不到private修饰到的方法
		 */
		Method[] method = personClass.getMethods();
		for (Object o :method) {
			System.out.println(o);
		}

		/**
		 * NoSuchMethodException:
		 * 这个方法只能获取pub修饰的方法
		 */
//		Method hehehe = personClass.getMethod("hehehe");
//		Method hehe = personClass.getMethod("hehe");
//		Method he = personClass.getMethod("he");
//		System.out.println(hehehe);//void，没有修饰符修饰的方法
//		System.out.println(hehe);//protected，没有修饰符修饰的方法
//		System.out.println(he);//private，没有修饰符修饰的方法

		Method save = personClass.getMethod("save");
		System.out.println(save);
		Person person = new Person();

		//调用这个save方法，需要传入一个类对象，如果有参数也可以在后面设置参数
		Object invoke = save.invoke(person);
//		Object invoke = save.invoke(person, null);
		System.out.println(invoke);

		//获取类名
		String name = personClass.getName();
		System.out.println("获取类名");
		System.out.println(name);

	}

	/**
	 * 反射读取配置文件创建对象
	 */
	@Test
	public void propertiesReflex(){
		Properties properties = new Properties();
		InputStream resourceAsStream = Reflex.class.getClassLoader().getResourceAsStream("reflex.properties");
		try {
			properties.load(resourceAsStream);
			String className = (String) properties.get("className");
			String methodName = (String) properties.get("methodName");
			Class<?> personClass = Class.forName(className);
			Method method = personClass.getMethod(methodName);
			Person person = new Person();
			method.invoke(person);

		} catch (Exception e) {
			e.printStackTrace();
		} finally {

		}
	}





}
